package org.beanutopia.constraint;

import com.google.common.base.Predicate;
import org.beanutopia.Property;
import org.beanutopia.exception.InvalidValueException;
import org.beanutopia.exception.NullValueException;

/**
 * @author ymeymann
 * @since Apr 25, 2007 6:42:27 PM
 */
public class Constraints {

  private static final Constraint<Object> NOT_NULL = new Constraint<Object>() {
      public <T> void validate(T value, Property<?, T> property) throws InvalidValueException {
        if (value == null) throw new NullValueException(property);
      }
    };

  public static Constraint<Object> notNull() { return NOT_NULL; }

  public static <V extends Comparable<V>> Constraint<V> greaterThan(V n) {
    return new CompareTo<V>(n) {
      public <T extends V> void validate(T value, Property<?, T> property) throws InvalidValueException {
        if (parameter().compareTo(value) >= 0) throw new InvalidValueException(value, property);
      }
    };
  }

  public static <V extends Comparable<V>> Constraint<V> greaterOrEqualTo(V n) {
    return new CompareTo<V>(n) {
      public <T extends V> void validate(T value, Property<?, T> property) throws InvalidValueException {
        if (parameter().compareTo(value) > 0) throw new InvalidValueException(value, property);
      }
    };
  }

  public static <V extends Comparable<V>> Constraint<V> lessThan(V n) {
    return new CompareTo<V>(n) {
      public <T extends V> void validate(T value, Property<?, T> property) throws InvalidValueException {
        if (parameter().compareTo(value) <= 0) throw new InvalidValueException(value, property);
      }
    };
  }

  public static <V extends Comparable<V>> Constraint<V> lessOrEqualTo(V n) {
    return new CompareTo<V>(n) {
      public <T extends V> void validate(T value, Property<?, T> property) throws InvalidValueException {
        if (parameter().compareTo(value) < 0) throw new InvalidValueException(value, property);
      }
    };
  }

  private static final Constraint<Integer> POSITIVE_INTEGER = greaterThan(0);
  public static Constraint<Integer> positiveInteger() { return POSITIVE_INTEGER; }

  private static final Constraint<Integer> NON_NEGATIVE_INTEGER = greaterOrEqualTo(0);
  public static Constraint<Integer> nonNegativeInteger() { return NON_NEGATIVE_INTEGER; }

  private static final Constraint<String> NOT_EMPTY = new Constraint<String>() {
      public <T extends String> void validate(T value, Property<?, T> property) throws InvalidValueException {
        if (value == null || value.length() == 0) throw new InvalidValueException(value, property);
      }
    };

  public static Constraint<String> notEmpty() { return NOT_EMPTY; }

  public static <V> Constraint<V> satisfies(Predicate<V> pred) {
    return new PredicateBasedConstraint<V>(pred);
  }
}
